'''
 * CaRComp Execution Environment
 * 
 * Copyright (C) 2011 Taylor L. Riche
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
'''

from carcomp.framework import component
from carcomp.apps.gamma.util import small_hash_map
from carcomp.apps.gamma import constants
from carcomp.framework import abstraction

class HashJoinAbs(abstraction.Abstraction):
    
    def __init__(self, name):
        abstraction.Abstraction.__init__(self, name)
        hj_comp = HashJoin('HashJoin_abs0')
        self.add_component(hj_comp)
        self.add_port('A', (hj_comp, 'A'))
        self.add_port('B', (hj_comp, 'B'))
        self.add_port('AB', (hj_comp, 'AB'), output=True)

class HashJoin(component.Implementation):
    '''
    classdocs
    '''
    
    debug = False

    def __init__(self, name):
        '''
        Constructor
        '''
        component.Implementation.__init__(self, name)
        self.add_port(component.Port('A', 'read_a'))
        self.add_port(component.Port('B', 'read_b'))
        self.add_port(component.Port('AB', '__OUT__'))
        self._finished = False
        self._a_table = small_hash_map.SmallHashMap(constants.SIZE)
        self._b_list = []
        
    def read_a(self, msg):
        '''
        Read in all A tuples, hash them, store them, and then set the B guard when done
        '''
        if HashJoin.debug is True:
            print('%s got %s'%(self._name, msg))
        if msg == 'DONE':
            self._finished = True
            self.read_b('FAKE')
        else:
            tuple = msg.split(':')
            jk = tuple[constants.JOIN_KEYA]
            self._a_table.put(jk, msg.rstrip())
    
    def read_b(self, msg):
        '''
        Read in each B tuple, hash it, and then check for joins
        '''
        if self._finished:
            if msg != 'FAKE':
                if HashJoin.debug is True:
                    print(self._name + ' BF: ' + msg)
                self._b_list.append(msg)
            for tuplestr in self._b_list:
                if HashJoin.debug is True:
                    print('looking at ' + tuplestr)
                tuple = tuplestr.split(':')
                jk = tuple[constants.JOIN_KEYB]
                if self._a_table.is_in(jk):
                    for atuplestr in self._a_table.get(jk):
                        if HashJoin.debug is True:
                            print('\tcomparing', atuplestr, tuplestr)
                        atuple = atuplestr.split(':')
                        if jk == atuple[constants.JOIN_KEYA]:
                            output_tuple = atuplestr + ':' + ':'.join(tuple[0:constants.JOIN_KEYB]) + ':' + ':'.join(tuple[constants.JOIN_KEYB+1:])
                            self.send_out('AB', output_tuple)
            self._b_list = []
        else:
            if msg != 'FAKE':
                if HashJoin.debug is True:
                    print(self._name + ' B: ' + msg)

                self._b_list.append(msg)